package com.ruoyi.framework.aspectj;

import com.ruoyi.common.annotation.AutoCache;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class CacheIntercepterAspect {

    public static final String CACHE_KEY_PREFIX = "AUTOCACHE";

    private static final Logger log = LoggerFactory.getLogger(CacheIntercepterAspect.class);

    @Autowired
    private RedisCache redisCache;

    @Around("@annotation(com.ruoyi.common.annotation.AutoCache)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        AutoCache methodCache = getAnnotation(joinPoint, AutoCache.class);
        String cacheKey = getCacheKey(joinPoint);

        String version = methodCache.version();
        if (version != null && version.length() > 0) {
            cacheKey = cacheKey + version;
        }

        Object obj = redisCache.getCacheObject(cacheKey);
        if (obj != null) {
            if (methodCache.isDelay()) {
                redisCache.expire(cacheKey, methodCache.expire());
            }
            log.info("自动从缓存获取结果，key [{}]", cacheKey);
            return obj;
        } else {
            log.debug("没有命中缓存，key [{}]", cacheKey);
            Object result = joinPoint.proceed(joinPoint.getArgs());
            if (result == null) {
                log.error("从缓存获取到的结果为空，key [{}]", cacheKey);
            } else {
                redisCache.setCacheObject(cacheKey, result, methodCache.expire(), TimeUnit.SECONDS);
            }
            return result;
        }
    }

    private String getCacheKey(ProceedingJoinPoint joinPoint) {
        return String.format("%s-%s.%s",
                CACHE_KEY_PREFIX,
                joinPoint.getSignature().toString().split("\\s")[1],
                StringUtils.join(joinPoint.getArgs(), ",")
        );
    }

    private <T extends Annotation> T getAnnotation(ProceedingJoinPoint jp, Class<T> clazz) {
        MethodSignature sign = (MethodSignature) jp.getSignature();
        Method method = sign.getMethod();
        return method.getAnnotation(clazz);
    }
}

